package com.lipaluma.test.db.internal;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceUtils;

import com.lipaluma.test.db.annotations.copy.CopyDbByCommandFrom;
import com.lipaluma.test.db.annotations.copy.CopySchema;
import com.lipaluma.test.db.exceptions.CleanException;

public class CopyUtils {
	private static Logger LOG = LoggerFactory.getLogger(CopyUtils.class);
	
	private static List<String> tablesCreated;
	
	public static void copyDb(CopyDbByCommandFrom copy) throws IOException, SQLException, InterruptedException {
		
		
	}

	public static void copySchema(CopySchema copy) throws IOException, SQLException {
		if(copy != null) {
			Connection connection = DataSourceUtils.getConnection(DbUtils.getDataSource());
			connection.createStatement().executeUpdate("create database if not exists "+copy.to());
			DatabaseMetaData dbmd = connection.getMetaData();
			List<String> tables = getTableNames(dbmd, copy.from());
			for (String table : tables) {
				copyTable(connection, copy.from(), copy.to(), table, copy.data(), copy.drop());
			}
//			createSchema(DbUtils.getDataSource(), copy.from(), copy.to(), copy.data(), copy.drop());
		}
	}
	
//	public static void createSchema(DataSource ds, String fromSchema, String schemaTo, boolean data, boolean drop) throws SQLException, IOException {
//		tablesCreated = new ArrayList<String>();
//		Connection connection = DataSourceUtils.getConnection(ds);
//		connection.createStatement().executeUpdate("create database "+schemaTo);
//		DatabaseMetaData dbmd = connection.getMetaData();
//		List<String> tableNames = getTableNames(dbmd, fromSchema);
//		Map<String, List<String>> mapDependencies = getTableDependencies(fromSchema, dbmd, tableNames);
//		for (String table : tableNames) {
//			createTableAfterDependencies(connection, fromSchema, schemaTo, table, mapDependencies, data, drop);
//		}		
//		DataSourceUtils.releaseConnection(connection, ds);
//	}

//	private static void createTableAfterDependencies(Connection connection, String schemaFrom, String schemaTo, String table, Map<String, List<String>> mapDependencies, boolean data, boolean drop) {
//		List<String> dependencies = mapDependencies.get(table);
//		if(dependencies != null) {
//			for (String dependencyTable : dependencies) {
//				createTableAfterDependencies(connection, schemaFrom, schemaTo, dependencyTable, mapDependencies, data, drop);
//			}
//		}
//		if(!tablesCreated.contains(table)){
//			copyTable(connection, schemaFrom, schemaTo, table, data, drop);
//			tablesCreated.add(table);
//		}
//	}

//	private static void copyTable(Connection connection, String schemaFrom, String schemaTo, String table, boolean data, boolean drop) {
//		try {
//			if(drop)
//				connection.createStatement().executeUpdate("drop table if exists "+schemaTo+"."+table);
//			ResultSet rs = connection.createStatement().executeQuery("show create table "+schemaFrom+"."+table);
//			connection.createStatement().executeQuery("use "+schemaTo);
//			if(rs.next()) {
//				String request = rs.getString(2).replaceFirst("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
//				connection.createStatement().executeUpdate(request);
//			} else
//				connection.createStatement().executeUpdate("create table if not exists "+schemaTo+"."+table+" like "+schemaFrom+"."+table);
//			if(data) {
//				connection.createStatement().executeUpdate("TRUNCATE TABLE "+schemaTo+"."+table);				
//				connection.createStatement().executeUpdate("insert into "+schemaTo+"."+table+" select * from "+schemaFrom+"."+table);
//			}
//		} catch (SQLException e) {
//			throw new CleanException("erreur lors de la création de la table "+table+" pour le schéma de test", e);
//		}
//	}

	private static void copyTable(Connection connection, String schemaFrom, String schemaTo, String table, boolean data, boolean drop) {
	try {
		if(drop)
			connection.createStatement().executeUpdate("drop table if exists "+schemaTo+"."+table);
		connection.createStatement().executeUpdate("create table if not exists "+schemaTo+"."+table+" like "+schemaFrom+"."+table);
		if(data) {
			connection.createStatement().executeUpdate("TRUNCATE TABLE "+schemaTo+"."+table);				
			connection.createStatement().executeUpdate("insert into "+schemaTo+"."+table+" select * from "+schemaFrom+"."+table);
		}
	} catch (SQLException e) {
		throw new CleanException("erreur lors de la création de la table "+table+" pour le schéma de test", e);
	}
}
	
	private static List<String> getTableNames(DatabaseMetaData dbmd, String schema) throws SQLException {
		String[] types = {"TABLE"};
		ResultSet rs = dbmd.getTables(schema, null, "%", types);
		List<String> tableNames = new ArrayList<String>();
		while(rs.next()) {
			tableNames.add(rs.getString(3));
		}
		return tableNames;
	}

	private static Map<String, List<String>> getTableDependencies(String schema, DatabaseMetaData dbmd, List<String> tableNames) throws SQLException {
		Map<String, List<String>> mapTableDependencies = new HashMap<String, List<String>>();
		for (String table : tableNames) {
			ResultSet rs = dbmd.getExportedKeys(schema, null, table);
			while(rs.next()) {
				List<String> dependencies = mapTableDependencies.get(rs.getString(7));
				if(dependencies == null) {
					dependencies = new ArrayList<String>();
					mapTableDependencies.put(rs.getString(7), dependencies);
				}
				dependencies.add(table);
			}
		}
		return mapTableDependencies;
	}

//	public static void copyDb(CopyDbByCommandFrom copy) throws IOException, SQLException, InterruptedException {
//		if(copy != null) {
//			Command dump = copy.dump();
//			File dumpFile = null;
//			if(StringUtils.isNotBlank(copy.pathDump())) {
//				File fileDestination = new File(copy.pathDump());
//				if(!fileDestination.exists())
//					fileDestination.mkdirs();
//				dumpFile = new File(fileDestination, "dump.sql");
//			}
//			
//			
//			StringBuilder command = new StringBuilder();
//			command.append("CMD.exe ").append(dump.cmd());
//			if(dumpFile != null) {
//				command.append(" > "+dumpFile.getAbsolutePath());
//			}
//			InputStream inputStream = null;
//			if(StringUtils.isNotBlank(dump.binPath())) {
//				File file = new File(dump.binPath());
//				Process exec = Runtime.getRuntime().exec(command.toString(), null, file);
//				if(dumpFile == null) {
//					inputStream = exec.getInputStream();
//				}
//				exec.waitFor();
//			} else {
//				Process exec = Runtime.getRuntime().exec(command.toString());
//				if(dumpFile == null)
//					inputStream = exec.getInputStream();
//				exec.waitFor();
//			}
//			
//			if(inputStream == null)
//				inputStream = new FileInputStream(dumpFile);
//			
//			StringReader reader = new StringReader("create database "+copy.schemaTest()+";\nuse "+copy.schemaTest()+"\n");
//			DataSource dataSource = DbUtils.getDataSource();
//			BatchUtils.executeBatch(dataSource, reader);
//			BatchUtils.executeBatch(dataSource, inputStream);
//		}
//	}

}
